Imports Clo = Enhancements.Core.Logging
Imports Ere = Enhancements.Basic.RegularExpressions
Imports Gen = System.Collections.Generic
Imports Glo = System.Globalization
Imports Iou = System.IO
Imports Ref = System.Reflection
Imports Reg = System.Text.RegularExpressions
Imports Sys = System
Imports Tex = System.Text
Imports Xsd = System.Xml.Schema
Imports W3c = System.Xml
Imports Vbn = Microsoft.VisualBasic

Namespace Enhancements.Basic.Expressions.Values
    ''' <summary>Represents a token extracted from an expression that has a decimal fixed-point value.</summary>
    ''' <remarks>A decimal value representation must use the decimal separator defined by the DecimalSeparatorRepresentation property, where applicable. Also it must end with the suffix specified by the TypeSpecifierRepresentation property. The given value must obey to the limits imposed by the Minimum and Maximum properties.</remarks>
    <Serializable(), DebuggerStepThrough()> _
    Public NotInheritable Class [Decimal]
        Inherits Number

        Private Sub New(ByVal _expression As System.String, ByVal _expressionBeginIndex As Sys.Int32, ByVal _expressionEndIndex As Sys.Int32, ByVal _value As System.Decimal)
            MyBase.New(_expression, _expressionBeginIndex, _expressionEndIndex, _value)
        End Sub

        ''' <summary>The associated framework type used for the token value storage.</summary>
        Public Shared ReadOnly Property UnderlyingType() As Sys.Type
            Get
                Dim _returnValue As Sys.Type = GetType(System.Decimal)

                Return _returnValue
            End Get
        End Property

        ''' <summary>The decimal separator used in the representation of these tokens.</summary>
        Public Shared ReadOnly Property DecimalSeparatorRepresentation() As System.String
            Get
                Dim _returnValue As System.String = "."

                Return _returnValue
            End Get
        End Property

        ''' <summary>The suffix that these tokens representations must end with.</summary>
        Public Shared ReadOnly Property TypeSpecifierRepresentation() As System.String
            Get
                Dim _returnValue As System.String = ___Texts.ToUpper("D")

                Return _returnValue
            End Get
        End Property

        ''' <summary>The minimum value accepted for a decimal fixed-point token.</summary>
        Public Shared ReadOnly Property Minimum() As System.Decimal
            Get
                Dim _returnValue As System.Decimal = 0D

                Return _returnValue
            End Get
        End Property

        ''' <summary>The maximum value accepted for a decimal fixed-point token.</summary>
        Public Shared ReadOnly Property Maximum() As System.Decimal
            Get
                Dim _returnValue As System.Decimal = Sys.Decimal.MaxValue

                Return _returnValue
            End Get
        End Property

        Private Shared Function __Parse(ByVal _expression As System.String, ByVal _expressionBeginIndex As Sys.Int32) As Sys.Object
            Dim _returnValue As Sys.Object = Nothing
            Dim _returnValueStringBuilder As Tex.StringBuilder = Nothing
            If _expression.IsNullNot("_expression", False) AndAlso _expression.IsEmptyNot("_expression", False) AndAlso _expressionBeginIndex.IsInRange("_expressionBeginIndex", 0, _expression.Length - 1, False) Then
                _returnValueStringBuilder = New Tex.StringBuilder(Sys.String.Empty)
                Dim _returnValueStringBuilderContainsAtLeastOneDigit As System.Boolean = False
                For _counter As Sys.Int32 = _expressionBeginIndex To _expression.Length - 1
                    If ___Texts.StartsWith(_expression.Substring(_counter), DecimalSeparatorRepresentation) Then
                        If ___Texts.IndexOf(_returnValueStringBuilder.ToString(), DecimalSeparatorRepresentation, 0) <> -1 Then
                            Exit For
                        Else
                            _returnValueStringBuilder.Append(DecimalSeparatorRepresentation)
                        End If
                    Else
                        If Sys.Char.IsDigit(_expression.Chars(_counter)) Then
                            _returnValueStringBuilder.Append(_expression.Chars(_counter))
                            _returnValueStringBuilderContainsAtLeastOneDigit = True
                        Else
                            If ___Texts.StartsWith(_expression.Substring(_counter), TypeSpecifierRepresentation) Then
                                _returnValueStringBuilder.Append(TypeSpecifierRepresentation)
                                Exit For
                            Else
                                Exit For
                            End If
                        End If
                    End If
                Next _counter
                If _returnValueStringBuilder.ToString().IsEmptyNot("_returnValueStringBuilder.ToString()", False) Then
                    If ___Texts.EndsWith(_returnValueStringBuilder.ToString(), TypeSpecifierRepresentation) Then
                        If Assert.IsTrue(_returnValueStringBuilderContainsAtLeastOneDigit, "_returnValueStringBuilderContainsAtLeastOneDigit", False) Then
                            _returnValueStringBuilder.Remove(_returnValueStringBuilder.ToString().Length - TypeSpecifierRepresentation.Length, TypeSpecifierRepresentation.Length)
                            Dim _dummy As System.Decimal = 0D
                            If Sys.Decimal.TryParse(_returnValueStringBuilder.ToString(), Glo.NumberStyles.AllowDecimalPoint, Glo.CultureInfo.InvariantCulture, _dummy) Then
                                If _dummy.IsInRange("_dummy", Minimum, Maximum, False) Then
                                    _returnValue = New [Decimal](_expression, _expressionBeginIndex, _expressionBeginIndex + _returnValueStringBuilder.ToString().Length + TypeSpecifierRepresentation.Length - 1, _dummy)
                                End If
                            End If
                        End If
                    End If
                End If
            End If
            If Assert.IsNull(_returnValue, "_returnValue", False) Then
                _returnValue = DecimalParseException.___Create(_expression, _expressionBeginIndex)
            End If

            Return _returnValue
        End Function

        ''' <summary>Parses an expression for a decimal fixed-point value starting by a begin index.</summary>
        ''' <param name="_expression">Expression to parse.</param>
        ''' <param name="_expressionBeginIndex">Expression begin index to use.</param>
        ''' <exception cref="DecimalParseException">The operation did not produce a valid token.</exception>
        ''' <returns> </returns>
        Public Overloads Shared Function Parse(ByVal _expression As System.String, ByVal _expressionBeginIndex As Sys.Int32) As [Decimal]
            Dim _returnValue As Sys.Object = __Parse(_expression, _expressionBeginIndex)
            If Assert.IsOfType(_returnValue, "_returnValue", GetType(DecimalParseException), False) Then
                DecimalParseException.___Throw(CType(_returnValue, DecimalParseException))
            End If

            Return CType(_returnValue, [Decimal])
        End Function

        ''' <summary>Tries to parse an expression for a decimal fixed-point value starting by a begin index.</summary>
        ''' <param name="_expression">Expression to parse.</param>
        ''' <param name="_expressionBeginIndex">Expression begin index to use.</param>
        ''' <param name="_result">The result of the operation if possible. If not, null is returned.</param>
        ''' <returns> </returns>
        Public Overloads Shared Function TryParse(ByVal _expression As System.String, ByVal _expressionBeginIndex As Sys.Int32, ByRef _result As [Decimal]) As System.Boolean
            Dim _returnValue As System.Boolean = False
            Dim _dummy As Sys.Object = __Parse(_expression, _expressionBeginIndex)
            If Assert.IsOfType(_dummy, "_dummy", GetType(DecimalParseException), False) Then
                _result = Nothing
                _returnValue = False
            Else
                _result = CType(_dummy, [Decimal])
                _returnValue = True
            End If

            Return _returnValue
        End Function

        Friend Overloads Shared Function ___AssertIsValidValue(ByVal _value As Sys.Object) As System.Boolean
            Dim _returnValue As System.Boolean = False
            If Assert.IsNullNot(_value, "_value", False) Then
                If Assert.IsOfType(_value, "_value", [Decimal].UnderlyingType, False) Then
                    Dim _valueDecimal As System.Decimal = CType(_value, System.Decimal)
                    If _valueDecimal.IsInRange("_valueDecimal", Minimum, Maximum, False) Then
                        _returnValue = True
                    End If
                End If
            End If

            Return _returnValue
        End Function

        ''' <summary>Determines the token's correct representation for use in an expression.</summary>
        ''' <returns> </returns>
        Public Overrides Function ToRepresentation() As System.String
            Dim _returnValue As System.String = __ToRepresentation(CType(Value, System.Decimal))

            Return _returnValue
        End Function

        ''' <summary>Determines the correct representation of a decimal fixed-point value for use in an expression.</summary>
        ''' <exception cref="DecimalRepresentationException">The operation did not produce a valid representation because of the input value nature.</exception>
        ''' <returns> </returns>
        Public Overloads Shared Function ToRepresentation(ByVal _value As System.Decimal) As System.String
            If Not ___AssertIsValidValue(_value) Then
                DecimalRepresentationException.___Throw(_value)
            End If

            Dim _returnValue As System.String = __ToRepresentation(_value)

            Return _returnValue
        End Function

        Private Shared Function __ToRepresentation(ByVal _value As System.Decimal) As System.String
            Dim _returnValue As System.String = ___Texts.ToUpper(_value)

            Return _returnValue
        End Function

        ''' <exception cref="IsNullException"> </exception>
        ''' <exception cref="IsListFilledNotException"> </exception>
        Friend Shared Function ___ParseAll(ByRef _tokens As Gen.List(Of Token)) As Sys.Int32
            _tokens.IsListFilled("_tokens", True)

            Dim _returnValue As Sys.Int32 = 0
            Dim _tokensNew As Gen.List(Of Token) = New Gen.List(Of Token)()
            For _counter1 As Sys.Int32 = 0 To _tokens.Count - 1
                If _tokens(_counter1).IsOfType("_tokens(_counter1)", GetType(Undetermined), False) Then
                    Dim _tokensToken As Undetermined = CType(_tokens(_counter1), Undetermined)
                    For _counter2 As Sys.Int32 = 0 To _tokensToken.ExpressionPart.Length - 1
                        Dim _decimal As [Decimal] = Nothing
                        If TryParse(_tokensToken.Expression, _tokensToken.ExpressionBeginIndex + _counter2, _decimal) Then
                            _tokensNew.Add(_decimal)
                            _counter2 += _decimal.ExpressionPart.Length - 1
                            _returnValue += 1
                        Else
                            Undetermined.___AppendNewToEndOrReplaceLastWithNew(_tokensNew, _tokensToken.Expression, _tokensToken.ExpressionBeginIndex + _counter2, _tokensToken.ExpressionBeginIndex + _counter2)
                        End If
                    Next _counter2
                Else
                    _tokensNew.Add(_tokens(_counter1))
                End If
            Next _counter1
            _tokens = _tokensNew

            Return _returnValue
        End Function

    End Class
End Namespace
